package dao

import (
	"database/sql"
	"fmt"
	gamedb "game/game-db"
	isql "game/game-db/mysql/sql"
	"game/game-db/orm"
	"game/game-db/orm/meta"
	"game/game-db/orm/metag"

	"go.uber.org/zap"
)

type DefaultBaseDao[T orm.IDbEntity] struct {
	OriginDao[T]

	sql isql.DefaultSql
}

func NewDefaultBaseDao[T orm.IDefaultDbEntity](database *sql.DB, entityTemplate T) gamedb.IDao[T] {
	entityMeta := meta.NewDefaultEntityMeta(entityTemplate)
	var dao DefaultBaseDao[T]
	dao.database = database
	dao.entityMeta = entityMeta
	dao.sql = isql.NewDefaultSql(entityMeta, entityMeta.TableName())
	//TODO 自动建表
	BuildTable(entityMeta, database, entityMeta.TableName())
	zap.L().Info(fmt.Sprintf("Table [%-25.25s]'s dao is initialized", entityMeta.TableName()))
	return &dao
}

func (t *DefaultBaseDao[T]) Sql(entity T) isql.ISql {
	return &t.sql
}

func (t *DefaultBaseDao[T]) Insert(entity T) error {
	if t.entityMeta.PrimaryKeyStrategy() == metag.AUTOWIRE {
		return insertWireAutoId(t.entityMeta, t.database, entity, t.sql.InsertSql())
	} else {
		return insert(t.entityMeta, t.database, entity, t.sql.InsertSql())
	}
}

func (t *DefaultBaseDao[T]) InsertAll(entities []T) {
	if t.entityMeta.PrimaryKeyStrategy() == metag.AUTOWIRE {
		insertAllWireAutoId(t.entityMeta, t.database, entities, t.sql.InsertSql())
	} else {
		insertAll(t.entityMeta, t.database, entities, t.sql.InsertHeadSql(), t.sql.InsertBodySql())
	}
}

func (t *DefaultBaseDao[T]) Update(entity T) {
	update(t.entityMeta, t.database, entity, t.sql.UpdateSql())
}

func (t *DefaultBaseDao[T]) UpdateAll(entities []T) {
	updateAll(t.entityMeta, t.database, entities, t.sql.UpdateSql())
}

func (t *DefaultBaseDao[T]) Delete(entity T) {
	delete(t.entityMeta, t.database, entity, t.sql.DeleteSql())
}

func (t *DefaultBaseDao[T]) DeleteAll(entities []T) {
	deleteAll(t.entityMeta, t.database, entities, t.sql.DeleteSql())
}

func (t *DefaultBaseDao[T]) TableName() string {
	return t.entityMeta.TableName()
}

func (t *DefaultBaseDao[T]) GetByPrimaryKey(key interface{}) (T, bool) {
	return t.query(t.sql.SelectSql(), key)
}

func (t *DefaultBaseDao[T]) QueryWhere(where string, args ...interface{}) []T {
	return t.queryList(fmt.Sprintf("%s %s", t.sql.SelectAllSql(), where), args...)
}

func (t *DefaultBaseDao[T]) All() []T {
	return t.queryList(t.sql.SelectAllSql())
}
